package cn.org.xwb.common.file.utils;

import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.MediaType;
import org.springframework.util.DigestUtils;

import java.io.*;
import java.util.Objects;

/**
 * 和文件相关的工具类
 */
@Log4j2
public class FileUtil {

    private FileUtil() {}

    /**
     * 获取当前项目的根路径
     * 代码参考：https://blog.csdn.net/zhyp29/article/details/123098048
     *
     * @return 当前项目的根路径
     */
    public static String getProjectRootPath() throws IOException {
        // 得到当前项目的根目录对象
        File dir = new File("");
        // 返回当前项目根目录的绝对路径
        return dir.getCanonicalPath();
    }

    /**
     * 获取当前项目的类根路径
     * 代码参考：https://blog.csdn.net/zhyp29/article/details/123098048
     *
     * @return 当前项目的类根路径
     */
    public static String getClassRootPath() throws IOException {
        // 获取当前项目类加载根目录对象
        File dir = new File(Objects.requireNonNull(FileUtil.class.getResource("/")).getPath());
        // 返回当前项目类加载根目录的绝对路径
        return dir.getCanonicalPath();
    }

    /**
     * 获取类路径下指定文件的绝对路径
     *
     * @param url 类路径下指定文件的访问路径
     * @return 类路径下指定文件的绝对路径
     */
    public static String getClassPathFileAbsolute(String url) throws IOException {
        return getClassRootPath() + url;
    }

    /**
     * 以字符形式读取文件内容
     *
     * @param filePath 文件路径
     * @return 文件的内容(字符串)
     */
    public static String readFileContentByChar(String filePath) {
        // 得到文件对象
        File file = new File(filePath);
        // 存储文件的完成内容
        StringBuilder fileContent = new StringBuilder();
        // try 资源自动管理，实现资源的自动关闭
        try (
                // 文件输入流
                FileInputStream fileInputStream = new FileInputStream(file);
                InputStreamReader reader = new InputStreamReader(fileInputStream);
                BufferedReader bufferedReader = new BufferedReader(reader);
        ) {
            // 读取文件内容的缓存
            String buf = "";
            // 读取文件内容
            while ((buf = bufferedReader.readLine()) != null) {
                // 保存读取的文件内容
                fileContent.append(buf);
            }
            log.info("以字符形式读取文件内容成功，读取的文件路径为：{}", filePath);
        } catch (Exception e) {
            log.error("以字符形式读取文件内容失败，读取的文件路径为：{}，\n错误信息：{}，\nerror：{}", filePath, e.getMessage(), e);
        }
        return fileContent.toString();
    }

    /**
     * 根据文件的后缀获取文件的类型
     *
     * @param extension 文件的后缀
     * @return 文件的类型
     */
    public static String getMimeType(String extension) {
        if (extension == null) extension = "";
        ContentInfo extensionMatch = ContentInfoUtil.findExtensionMatch(extension);
        String mimeType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
        if (extensionMatch != null) mimeType = extensionMatch.getMimeType();
        return mimeType;
    }

    /**
     * 根据 mimeType 获取文件的后缀
     *
     * @param mimeType mimeType
     * @return 文件的后缀
     */
    public static String getExtensionByMimeType(String mimeType) {
        if (mimeType == null) mimeType = "";
        ContentInfo mimeTypeMatch = ContentInfoUtil.findMimeTypeMatch(mimeType);
        String[] fileExtensions = mimeTypeMatch.getFileExtensions();
        if (Objects.isNull(fileExtensions)) return "";
        return fileExtensions[0];
    }

    /**
     * 获取文件的后缀
     *
     * @param fileName 文件名
     * @return 文件的后缀
     */
    public static String getExtensionByFilename(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 获取文件的 MD5
     *
     * @param file 文件对象
     * @return 获取失败返回 null，否则返回文件的 MD5
     */
    public static String getFileMD5(File file) {
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            String md5 = DigestUtils.md5DigestAsHex(fileInputStream);
            log.info("获取文件的 MD5 成功，文件路径为：{}", file.getAbsolutePath());
            return md5;
        } catch (IOException e) {
            log.error("获取文件的 MD5 失败，文件路径为：{}，\n错误信息：{}，\nerror：{}", file.getAbsolutePath(), e.getMessage(), e);
            return null;
        }
    }

}
